package com.tiennt.android.droidcamreader;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.Region;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.MotionEvent;
import android.view.View;

public class CropView extends View {

	/** Min width of crop rectangle */
	public static final int MIN_WIDTH = 40;

	/** Min height of crop rectangle */
	public static final int MIN_HEIGHT = 40;

	/** Left edge of crop rectangle */
	public static final int LEFT_EDGE = 4;

	/** Top edge of crop rectangle */
	public static final int TOP_EDGE = 4;

	public static final int AREA_LEFT_TOP = 0;
	public static final int AREA_RIGHT_TOP = 1;
	public static final int AREA_RIGHT_BOTTOM = 2;
	public static final int AREA_LEFT_BOTTOM = 3;

	public static final String STROKE_COLOR = "#C9CEFF";
	public static final String FILL_COLOR = "#FFFFFF";

	private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
	private Context mContext;
	private int MAX_WIDTH;
	private int MAX_HEIGHT;

	float mTop;
	float mLeft;
	float mRight;
	float mBottom;
	boolean locked = false;

	float mLastTouchX;
	float mLastTouchY;
	float mPointerArea;
	float mLastLeft;
	float mLastTop;
	Rect innerRect = new Rect();
	Rect outerRect = new Rect();

	public CropView(Context context) {
		super(context);
		// TODO Auto-generated constructor stub
		mContext = context;
		init();
	}

	public CropView(Context context, AttributeSet attrs) {
		super(context, attrs);
		// TODO Auto-generated constructor stub
		mContext = context;
		init();
	}

	public CropView(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		// TODO Auto-generated constructor stub
		mContext = context;
		init();
	}

	public void init() {
		DisplayMetrics metrics = mContext.getResources().getDisplayMetrics();
		MAX_WIDTH = metrics.widthPixels;
		MAX_HEIGHT = metrics.heightPixels;

		mLeft = MAX_WIDTH / 4;
		mTop = MAX_HEIGHT / 4;
		mRight = MAX_WIDTH - mLeft;
		mBottom = MAX_HEIGHT - mTop;

		mPaint.setDither(true);

	}

	/**
	 * Set paint param to stroke
	 * 
	 * @param color
	 *            paint's color
	 * @param width
	 *            stroke width
	 */
	public void setPaintToStroke(String color, int width) {
		mPaint.setStyle(Paint.Style.STROKE);
		mPaint.setStrokeWidth(width);
		mPaint.setColor(Color.parseColor(color));
	}

	/**
	 * Set paint param to fill
	 * 
	 * @param color
	 *            color to fill
	 */
	public void setPaintToFill(String color) {
		mPaint.setStyle(Paint.Style.FILL);
		mPaint.setColor(Color.parseColor(color));
	}

	@Override
	protected void onDraw(Canvas canvas) {
		// TODO Auto-generated method stub
		super.onDraw(canvas);

		setPaintToStroke(STROKE_COLOR, 2);
		canvas.drawRect(mLeft, mTop, mRight, mBottom, mPaint);

		innerRect.set((int) mLeft, (int) mTop, (int) mRight, (int) mBottom);

		canvas.clipRect(innerRect, Region.Op.DIFFERENCE);

		canvas.drawARGB(128, 0, 0, 0);

		outerRect.set(0, 0, canvas.getWidth(), canvas.getHeight());

		canvas.clipRect(outerRect, Region.Op.REPLACE);

		// Draw rect
		setPaintToStroke(STROKE_COLOR, 4);
		canvas.drawRect(mLeft - 12, mTop - 12, mLeft + 12, mTop + 12, mPaint);

		canvas.drawRect(mLeft - 12, mBottom - 12, mLeft + 12, mBottom + 12,
				mPaint);

		canvas.drawRect(mRight - 12, mTop - 12, mRight + 12, mTop + 12, mPaint);

		canvas.drawRect(mRight - 12, mBottom - 12, mRight + 12, mBottom + 12,
				mPaint);

		// Fill rect
		setPaintToFill(FILL_COLOR);
		canvas.drawRect(mLeft - 10, mTop - 10, mLeft + 10, mTop + 10, mPaint);

		canvas.drawRect(mLeft - 10, mBottom - 10, mLeft + 10, mBottom + 10,
				mPaint);

		canvas.drawRect(mRight - 10, mTop - 10, mRight + 10, mTop + 10, mPaint);

		canvas.drawRect(mRight - 10, mBottom - 10, mRight + 10, mBottom + 10,
				mPaint);
	}

	public void lock() {
		locked = true;
	}

	public void release() {
		locked = false;
	}

	@Override
	public boolean onTouchEvent(MotionEvent event) {
		// TODO Auto-generated method stub
		if (!locked) {
			float x = event.getX();
			float y = event.getY();

			switch (event.getAction()) {
			case MotionEvent.ACTION_DOWN:
				mLastTouchX = x;
				mLastTouchY = y;
				mLastLeft = mLeft;
				mLastTop = mTop;

				if (x < MAX_WIDTH / 2) {
					if (y < MAX_HEIGHT / 2) {
						mPointerArea = AREA_LEFT_TOP;
					} else {
						mPointerArea = AREA_LEFT_BOTTOM;
					}
				} else {
					if (y < MAX_HEIGHT / 2) {
						mPointerArea = AREA_RIGHT_TOP;
					} else {
						mPointerArea = AREA_RIGHT_BOTTOM;
					}
				}

				break;

			case MotionEvent.ACTION_MOVE:
				if (mPointerArea == AREA_LEFT_TOP) {
					float deltaX = x - mLastTouchX;
					float deltaY = y - mLastTouchY;

					mLeft = mLastLeft + deltaX;
					mTop = mLastTop + deltaY;

					if (mLeft < LEFT_EDGE) {
						mLeft = LEFT_EDGE;
					} else if (mLeft > (MAX_WIDTH - MIN_WIDTH) / 2) {
						mLeft = (MAX_WIDTH - MIN_WIDTH) / 2;
					}

					if (mTop < TOP_EDGE) {
						mTop = TOP_EDGE;
					} else if (mTop > (MAX_HEIGHT - MIN_HEIGHT) / 2) {
						mTop = (MAX_HEIGHT - MIN_HEIGHT) / 2;
					}

					mRight = MAX_WIDTH - mLeft;
					mBottom = MAX_HEIGHT - mTop;
					invalidate();
				} else if (mPointerArea == AREA_RIGHT_TOP) {
					float deltaX = x - mLastTouchX;
					float deltaY = y - mLastTouchY;

					mLeft = mLastLeft - deltaX;
					mTop = mLastTop + deltaY;

					if (mLeft < LEFT_EDGE) {
						mLeft = LEFT_EDGE;
					} else if (mLeft > (MAX_WIDTH - MIN_WIDTH) / 2) {
						mLeft = (MAX_WIDTH - MIN_WIDTH) / 2;
					}

					if (mTop < TOP_EDGE) {
						mTop = TOP_EDGE;
					} else if (mTop > (MAX_HEIGHT - MIN_HEIGHT) / 2) {
						mTop = (MAX_HEIGHT - MIN_HEIGHT) / 2;
					}

					mRight = MAX_WIDTH - mLeft;
					mBottom = MAX_HEIGHT - mTop;
					invalidate();
				} else if (mPointerArea == AREA_RIGHT_BOTTOM) {
					float deltaX = x - mLastTouchX;
					float deltaY = y - mLastTouchY;

					mLeft = mLastLeft - deltaX;
					mTop = mLastTop - deltaY;
					if (mLeft < LEFT_EDGE) {
						mLeft = LEFT_EDGE;
					} else if (mLeft > (MAX_WIDTH - MIN_WIDTH) / 2) {
						mLeft = (MAX_WIDTH - MIN_WIDTH) / 2;
					}

					if (mTop < TOP_EDGE) {
						mTop = TOP_EDGE;
					} else if (mTop > (MAX_HEIGHT - MIN_HEIGHT) / 2) {
						mTop = (MAX_HEIGHT - MIN_HEIGHT) / 2;
					}
					mRight = MAX_WIDTH - mLeft;
					mBottom = MAX_HEIGHT - mTop;
					invalidate();
				} else if (mPointerArea == AREA_LEFT_BOTTOM) {
					float deltaX = x - mLastTouchX;
					float deltaY = y - mLastTouchY;

					mLeft = mLastLeft + deltaX;
					mTop = mLastTop - deltaY;
					if (mLeft < LEFT_EDGE) {
						mLeft = LEFT_EDGE;
					} else if (mLeft > (MAX_WIDTH - MIN_WIDTH) / 2) {
						mLeft = (MAX_WIDTH - MIN_WIDTH) / 2;
					}

					if (mTop < TOP_EDGE) {
						mTop = TOP_EDGE;
					} else if (mTop > (MAX_HEIGHT - MIN_HEIGHT) / 2) {
						mTop = (MAX_HEIGHT - MIN_HEIGHT) / 2;
					}
					mRight = MAX_WIDTH - mLeft;
					mBottom = MAX_HEIGHT - mTop;
					invalidate();
				}
				break;

			default:
				break;
			}
		}

		return true;
	}

	public float getCropTop() {
		return mTop;
	}

	public float getCropLeft() {
		return mLeft;
	}

	public float getCropRight() {
		return mRight;
	}

	public float getCropBottom() {
		return mBottom;
	}

	public Rect getCropRectangle() {
		return new Rect((int) mLeft, (int) mTop, (int) mRight, (int) mBottom);
	}
}
